package com.dymall.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dymall.common.exception.BizIllegalException;
import com.dymall.common.utils.BeanUtils;
import com.dymall.common.utils.CollUtils;
import com.dymall.common.utils.UserContext;
import com.dymall.domain.dto.CartFormDTO;
import com.dymall.domain.dto.ItemDTO;
import com.dymall.domain.po.Cart;
import com.dymall.domain.vo.CartVO;
import com.dymall.mapper.CartMapper;
import com.dymall.service.CartService;
import com.dymall.service.ItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements CartService {
    private final ItemService itemService;
    private final StringRedisTemplate stringRedisTemplate;

    @Override
    public List<CartVO> queryMyCarts() {
        // 1、从redis中查询购物车列表缓存
        String key = "cart:" + UserContext.getUser();
        String cartList = stringRedisTemplate.opsForValue().get(key);
        if(StrUtil.isNotBlank(cartList)){
            // 2、存在，直接返回
            return JSONUtil.toList(cartList, CartVO.class);
        }
        // 3、不存在
        // 3.1、检验是否为空值""
        if(cartList != null){
            return Collections.emptyList();
        }
        // 3.2、不为空值，查购物车列表
        List<Cart> carts = lambdaQuery().eq(Cart::getUserId, UserContext.getUser()).list();
        if(carts == null || carts.isEmpty()){
            //3.3、购物车为空，写入redis并返回空集合
            stringRedisTemplate.opsForValue().set(key, "", 2, TimeUnit.MINUTES);
            return Collections.emptyList();
        }
        //转为购物车视图
        List<CartVO> vos = BeanUtils.copyList(carts, CartVO.class);
        //处理VO中的商品信息
        handleCartItems(vos);

        // 4、写入redis
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(vos), 10 , TimeUnit.MINUTES);
        return vos;
    }

    @Override
    public void addItemToCart(CartFormDTO cartFormDTO) {
        String key = "cart:" + UserContext.getUser();
        //获取登录用户
        Long userId = UserContext.getUser();

        //判断商品在购物车中是否已存在
        if(lambdaQuery()
                .eq(Cart::getUserId,userId)
                .eq(Cart::getItemId,cartFormDTO.getItemId())
                .count() > 0){
            //存在，商品数量加1
            lambdaUpdate().setSql("set num = num + 1")
                    .eq(Cart::getUserId,userId)
                    .eq(Cart::getItemId,cartFormDTO.getItemId())
                    .update();
            //删除redis中的缓存
            stringRedisTemplate.delete(key);
            return;
        }

        //不存在，判断购物车是否已满
        isFull(userId);

        Cart cart = BeanUtils.copyBean(cartFormDTO, Cart.class);
        cart.setUserId(userId);
        // 1、更新数据库
        save(cart);
        // 2、删除redis中的缓存
        stringRedisTemplate.delete(key);
    }

    @Override
    public void deleteCartItemByIds(Collection<Long> ids) {
        //构建删除条件，userId和itemId
        LambdaQueryWrapper<Cart> wrapper = new QueryWrapper<Cart>().lambda()
                .in(Cart::getItemId, ids)
                .eq(Cart::getUserId, UserContext.getUser());
        // 1、更新数据库,删除
        remove(wrapper);
        // 2、删除redis中的缓存
        stringRedisTemplate.delete("cart:" + UserContext.getUser());
    }

    private void isFull(Long userId) {
        if(lambdaQuery()
                .eq(Cart::getUserId,userId)
                .count() > 20){
            throw new BizIllegalException(StrUtil.format("用户购物车课程不能超过{}", 20));
        }
    }


    private void handleCartItems(List<CartVO> vos) {
        // 1.获取商品id,将其封装到Set集合中，去重，避免重复查询
        Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
        // 2.查询商品
        List<ItemDTO> items = itemService.queryItemByIds(itemIds);
        if (CollUtils.isEmpty(items)) {
            return;
        }
        // 3.转为 id 到 item的map
        Map<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));
        // 4.写入vo
        for (CartVO v : vos) {
            ItemDTO item = itemMap.get(v.getItemId());
            if (item == null) {
                continue;
            }
            v.setNewPrice(item.getPrice());
            v.setStatus(item.getStatus());
            v.setStock(item.getStock());
        }
    }
}
